#include <errno.h>
#include <stdio.h> 
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

//#include "net_common.h"
//#include "net_params.h" 

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "lwip/sockets.h" 

#include <time.h> 
//#include "hi_time.h"  
//#include <hi_types_base.h> 
//#include <hi_wifi_api.h>
//#include <hi_early_debug.h> 

#include "iot_time.h"
#include "los_base.h"

#ifndef close
#define close(fd) lwip_close(fd)
#endif

#define     NTPIPADDR       "182.92.12.11"  //"52.231.114.183"
#define     NTPPORT         123

#define NTP_TIMESTAMP_DELTA 2208988800ull 

//extern
uint32_t NTPTimeStamp = 0; // 通过ntp读取的当前网络时间戳
uint32_t NTPSysTick = 0;   // 读取ntp时的系统tick，通过hi_get_tick()获取

bool GetNTPFlag; 

// 获取ntp时间戳
void getNtpTime(void) {  

    uint32_t NTP_Time;
    unsigned char buf[48];//存储NTP服务器返回的数据
    unsigned char NTP_Data[]=
     { 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
       0x0d6, 0x06d, 0x0d9, 0x00, 0x00, 0x00, 0x00, 0x00};
    ; //48字节的报文
    
    ssize_t retval = 0;
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // UDP socket  

    // 设置超时
    // https://blog.csdn.net/u011146511/article/details/56042666 
    struct timeval timeout = {5, 0};  
    retval = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
    if (retval ==-1) { 
        printf("<=! setsockopt failed!  \r\n");
        goto do_cleanup;
    } 
    
    struct sockaddr_in toAddr = {0};
    toAddr.sin_family = AF_INET;
    toAddr.sin_port = htons(NTPPORT); // 端口号，从主机字节序转为网络字节序
    if (inet_pton(AF_INET, NTPIPADDR, &toAddr.sin_addr) <= 0) { 
        // 将主机IP地址从“点分十进制”字符串 转化为 标准格式（32位整数）
        printf("<=! inet_pton failed!  \r\n");
        goto do_cleanup;
    }  

 ntp_loop:    
    
    // UDP socket 是 “无连接的” ，因此每次发送都必须先指定目标主机和端口，主机可以是多播地址
    retval = sendto(sockfd, NTP_Data, 48, 0, (struct sockaddr *)&toAddr, sizeof(toAddr));
    
    // 约10秒后有时间返回值
    if (retval < 0) {
        printf("==> getNtpTime() ... wait ntp time. \r\n");
        goto do_cleanup;
    }
    printf("==> getNtpTime() ... sendto. \r\n");
    
    /*
    printf("-- getNtpTime() ... send NTP message %ld done!\r\n", retval);
    for(uint8_t i = 0;i<48;i++){
        printf("%02x\t",(unsigned char)NTP_Data[i]);
        if( (i+1) % 8 == 0 )
        printf("\r\n");
    }
    */
    struct sockaddr_in fromAddr = {0};
    socklen_t fromLen = sizeof(fromAddr);
    
    // UDP socket 是 “无连接的” ，因此每次接收时前并不知道消息来自何处，通过 fromAddr 参数可以得到发送方的信息（主机、端口号）
    retval = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&fromAddr, &fromLen);
    if (retval <= 0) {
        printf("=!= getNtpTime().recvfrom failed (timeout) or abort, %ld, %d!\r\n", retval, errno);
        //goto do_cleanup;
        goto ntp_loop;  // 再来一次
    }
    printf("==> getNtpTime() ... recvfrom. \r\n");
    
    NTP_Time = buf[40]<<24 | buf[40+1]<<16|buf[40+2]<<8 |buf[40+3];
    NTPTimeStamp = NTP_Time - NTP_TIMESTAMP_DELTA;  // ntp时间戳，精确到秒
    NTPSysTick = 0;// hi_get_tick();                     // 系统当前tick

    printf("<== getNtpTime().NTPTimeStamp = %ld\n", NTPTimeStamp);   

    //response[retval] = '\0';
    /*
    printf("recv UDP message {%s} %ld done!\r\n", buf, retval);
    printf("peer info: ipaddr = %s, port = %d\r\n", inet_ntoa(fromAddr.sin_addr), ntohs(fromAddr.sin_port));
    for(uint8_t i = 0;i<48;i++) {
        printf("%02x\t",(unsigned char)buf[i]);
        if( (i+1) % 8 == 0 )
        printf("\r\n");
    }
    */
    GetNTPFlag = false;

do_cleanup:
    GetNTPFlag = false;
    //printf("do_cleanup...\r\n");
    close(sockfd); 
}

// 当前时间戳
uint32_t get_ntp_client(void){
    if(NTPSysTick == 0){
        getNtpTime();
    }

    uint32_t currTick = 0;// hi_get_tick();  // 当前tick
    uint32_t ret = (currTick - NTPSysTick) / 100 + NTPTimeStamp;
    return ret;
}

 
// 设备开机以来的时间戳
uint32_t get_local_client(void){
    if(NTPSysTick == 0){
        NTPSysTick = 0;// hi_get_tick();                     // 系统当前tick
    }

    uint32_t currTick = 0;// hi_get_tick();  // 当前tick 
    uint32_t ret = (currTick - NTPSysTick) / 100;
    return ret;
} 


// 获取时间戳：YYYYMMDDTHHMMSSZ，形如20211031T181759Z
//    char tms[32];
//    currTimeStamp(&tms); 
void currTimeStamp(char *tms)   
{ 
    //uint32_t t = tls_ntp_client();  //获取时间
    uint32_t t = get_ntp_client();  // 
    struct tm *tblock;
    tblock = localtime((const time_t *)&t);   //北京时间补偿8小时
    if(tblock->tm_hour>15) 
        sprintf(tms, "%04d%02d%02d%s%02d%02d%02d%s",
            tblock->tm_year + 1900, tblock->tm_mon + 1, tblock->tm_mday + 1, "T", tblock->tm_hour - 16, tblock->tm_min, tblock->tm_sec, "Z");
    else
        sprintf(tms, "%04d%02d%02d%s%02d%02d%02d%s",
            tblock->tm_year + 1900, tblock->tm_mon + 1, tblock->tm_mday, "T", tblock->tm_hour + 8, tblock->tm_min, tblock->tm_sec, "Z");

    //printf("=== currTimeStamp: %s\r\n", tms);
}

// 获取时间戳：YYYYMMDDHH，精确到小时
//    char hour[32];
//    currTimeHour(&hour); 
void currTimeHour(char* hour)    
{
    //uint32_t t = tls_ntp_client(); //获取时间 
    uint32_t t = get_ntp_client();  // 
    struct tm *tblock;    
    tblock = localtime((const time_t *)&t); 
    if(tblock->tm_hour>15) 
        sprintf(hour, "%04d%02d%02d%02d",
            tblock->tm_year + 1900, tblock->tm_mon + 1, tblock->tm_mday + 1, tblock->tm_hour - 16);
    else 
        sprintf(hour, "%04d%02d%02d%02d",
            tblock->tm_year + 1900, tblock->tm_mon + 1, tblock->tm_mday, tblock->tm_hour + 8);
    //printf("=== currTimeHour: %s\r\n", hour); 
} 

// 获取当前的小时和分钟，形成：23(h)*100 + 30(m) = 2300 的整数
int currHourMin(void)    
{
    int hm = 0;

    uint32_t t = get_ntp_client();  // 
    struct tm *tblock;    
    tblock = localtime((const time_t *)&t); 
    if(tblock->tm_hour>15)
        hm = (tblock->tm_hour - 16) * 100 + tblock->tm_min; 
    else  
        hm = (tblock->tm_hour + 8) * 100 + tblock->tm_min;  
    return hm;
} 



//========== 
 
// 读取设备 mac 地址 =====
#define MAC_ADDR_FMT "%02x%02x%02x%02x%02x%02x"
#define mac2str(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] 

uint8_t hi3861_mac_addr[7] = {0}; // 6 mac len   

// get hi3861 mac addr 
uint32_t hi3861_get_mac_addr(char *mac) { 
    if (hi_wifi_get_macaddr((char*)hi3861_mac_addr, 6) != 0) {  // 6 mac len  
        return -1; //HI_ERR_FAILURE;
    }
    //printf("<=+ MAC: " MAC_ADDR_FMT "\r\n", mac2str(hi3861_mac_addr));

    static char macAddress[13] = {0};
    snprintf(macAddress, sizeof(macAddress), MAC_ADDR_FMT, mac2str(hi3861_mac_addr));

    // 复制到全局变量中
    sprintf(mac, "%s", macAddress); 
     
    return 1;
}
// end mac =====

// 自定义定时器
 /*
int hm_timer(int ms, int id)
{
   
	static int t[10];
	if (clock() - t[id] > ms)
	{
		t[id] = clock();
		return 1;
	}
	return 0;
    
}
*/ 

// 调用方法：
//if (hm_timer(1000*3, 0) == 1)    
//{
//	方法();
//}